﻿<!DOCTYPE html>
<html class="theme theme-white">
<head>
<meta charset="utf-8">
<title>Redis面试题</title>
<link href="https://www.zybuluo.com/static/assets/template-theme-white.css" rel="stylesheet" media="screen">
<style type="text/css">

#wmd-preview h1  {
    color: #0077bb; /* 将标题改为蓝色 */
}</style>
</head>
<body class="theme theme-white">
<div id="wmd-preview" class="wmd-preview wmd-preview-full-reader"><div class="md-section-divider"></div><div class="md-section-divider"></div><h1 data-anchor-id="76gp" id="redis面试题">Redis面试题</h1><p data-anchor-id="z46k"><code>Java面试题</code></p><hr><div class="md-section-divider"></div><h3 data-anchor-id="sal6" id="什么是redis">什么是redis?</h3><p data-anchor-id="rkj8">Redis 是一个基于内存的高性能key-value数据库。</p><div class="md-section-divider"></div><h3 data-anchor-id="v5d7" id="为什么redis是单进程单线程的">为什么Redis是单进程单线程的？</h3><p data-anchor-id="9r2a">redis利用队列技术将并发访问变为串行访问，消除了传统数据库串行控制的开销</p><div class="md-section-divider"></div><h3 data-anchor-id="wqpb" id="使用redis有哪些好处">使用redis有哪些好处？</h3><p data-anchor-id="dj23">(1) 速度快，因为数据存在内存中，类似于HashMap，HashMap的优势就是查找和操作的时间复杂度都是O(1)  <br>
(2) 支持丰富数据类型，支持string，list，set，sorted set，hash  <br>
(3) 支持事务，操作都是原子性，所谓的原子性就是对数据的更改要么全部执行，要么全部不执行  <br>
(4) 丰富的特性：可用于缓存，消息，按key设置过期时间，过期后将会自动删除</p><div class="md-section-divider"></div><h3 data-anchor-id="2bvx" id="为什么redis需要把所有数据放到内存中">为什么redis需要把所有数据放到内存中？</h3><p data-anchor-id="5wiz">Redis为了达到最快的读写速度将数据都读到内存中，并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。如果不将数据放在内存中，磁盘I/O速度为严重影响redis的性能。在内存越来越便宜的今天，redis将会越来越受欢迎。 <br>
如果设置了最大使用的内存，则数据已有记录数达到内存限值后不能继续插入新值。</p><div class="md-section-divider"></div><h3 data-anchor-id="h912" id="虚拟内存">虚拟内存</h3><p data-anchor-id="thvy">当你的key很小而value很大时,使用VM的效果会比较好.因为这样节约的内存比较大. <br>
当你的key不小时,可以考虑使用一些非常方法将很大的key变成很大的value,比如你可以考虑将key,value组合成一个新的value. <br>
vm-max-threads这个参数,可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延迟,但是对数据完整性有很好的保证.</p><p data-anchor-id="56hx">自己测试的时候发现用虚拟内存性能也不错。如果数据量很大，可以考虑分布式或者其他数据库</p><div class="md-section-divider"></div><h3 data-anchor-id="es2o" id="分布式">分布式</h3><p data-anchor-id="l581">redis支持主从的模式。原则：Master会将数据同步到slave，而slave不会将数据同步到master。Slave启动时会连接master来同步数据。</p><p data-anchor-id="8pv9">这是一个典型的分布式读写分离模型。我们可以利用master来插入数据，slave提供检索服务。这样可以有效减少单个机器的并发访问数量</p><div class="md-section-divider"></div><h3 data-anchor-id="33an" id="读写分离模型">读写分离模型</h3><p data-anchor-id="be1z">通过增加Slave DB的数量，读的性能可以线性增长。为了避免Master DB的单点故障，集群一般都会采用两台Master DB做双机热备，所以整个集群的读和写的可用性都非常高。 <br>
读写分离架构的缺陷在于，不管是Master还是Slave，每个节点都必须保存完整的数据，如果在数据量很大的情况下，集群的扩展能力还是受限于单个节点的存储能力，而且对于Write-intensive类型的应用，读写分离架构并不适合。</p><div class="md-section-divider"></div><h3 data-anchor-id="v4j6" id="数据分片模型">数据分片模型</h3><p data-anchor-id="vpb9">为了解决读写分离模型的缺陷，可以将数据分片模型应用进来。</p><p data-anchor-id="22si">可以将每个节点看成都是独立的master，然后通过业务实现数据分片。</p><p data-anchor-id="dhfy">结合上面两种模型，可以将每个master设计成由一个master和多个slave组成的模型。</p><div class="md-section-divider"></div><h3 data-anchor-id="sx3z" id="redis的回收策略">Redis的回收策略</h3><p data-anchor-id="mjxj">volatile-lru：从已设置过期时间的数据集（server.db[i].expires）中挑选最近最少使用的数据淘汰</p><p data-anchor-id="9cgy">volatile-ttl：从已设置过期时间的数据集（server.db[i].expires）中挑选将要过期的数据淘汰</p><p data-anchor-id="jzls">volatile-random：从已设置过期时间的数据集（server.db[i].expires）中任意选择数据淘汰</p><p data-anchor-id="b36k">allkeys-lru：从数据集（server.db[i].dict）中挑选最近最少使用的数据淘汰</p><p data-anchor-id="99a9">allkeys-random：从数据集（server.db[i].dict）中任意选择数据淘汰</p><p data-anchor-id="m25v">no-enviction（驱逐）：禁止驱逐数据</p><div class="md-section-divider"></div><h3 data-anchor-id="fd5f" id="redis相比memcached有哪些优势">redis相比memcached有哪些优势？</h3><p data-anchor-id="bjx0">(1) memcached所有的值均是简单的字符串，Redis作为其替代者，支持更为丰富的数据类型  <br>
(2) redis的速度比memcached快很多  <br>
(3) redis可以持久化其数据</p><div class="md-section-divider"></div><h3 data-anchor-id="ce0u" id="memcache与redis的区别都有哪些">Memcache与Redis的区别都有哪些？</h3><p data-anchor-id="0i8w">1)、存储方式  <br>
Memecache把数据全部存在内存之中，断电后会挂掉，数据不能超过内存大小。  <br>
Redis有部份存在硬盘上，这样能保证数据的持久性。  <br>
2)、数据支持类型  <br>
Memcache对数据类型支持相对简单。  <br>
Redis有复杂的数据类型。  <br>
3)、使用底层模型不同  <br>
它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。  <br>
Redis直接自己构建了VM 机制 ，因为一般的系统调用系统函数的话，会浪费一定的时间去移动和请求。</p><div class="md-section-divider"></div><h3 data-anchor-id="nfeg" id="redis常见性能问题和解决方案">redis常见性能问题和解决方案：</h3><p data-anchor-id="qon7">(1) Master最好不要做任何持久化工作，如RDB内存快照和AOF日志文件  <br>
(2) 如果数据比较重要，某个Slave开启AOF备份数据，策略设置为每秒同步一次  <br>
(3) 为了主从复制的速度和连接的稳定性，Master和Slave最好在同一个局域网内  <br>
(4) 尽量避免在压力很大的主库上增加从库  <br>
(5) 主从复制不要用图状结构，用单向链表结构更为稳定，即：Master &lt;- Slave1 &lt;- Slave2 &lt;- Slave3…  <br>
这样的结构方便解决单点故障问题，实现Slave对Master的替换。如果Master挂了，可以立刻启用Slave1做Master，其他不变。</p><div class="md-section-divider"></div><h3 data-anchor-id="byxg" id="mysql里有2000w数据redis中只存20w的数据如何保证redis中的数据都是热点数据">mySQL里有2000w数据，redis中只存20w的数据，如何保证redis中的数据都是热点数据？</h3><p data-anchor-id="lmo4">相关知识：redis 内存数据集大小上升到一定大小的时候，就会施行数据淘汰策略。redis 提供 6种数据淘汰策略：</p><ul data-anchor-id="f9xi">
<li>volatile-lru：从已设置过期时间的数据集（server.db[i].expires）中挑选最近最少使用的数据淘汰</li>
<li>volatile-ttl：从已设置过期时间的数据集（server.db[i].expires）中挑选将要过期的数据淘汰</li>
<li>volatile-random：从已设置过期时间的数据集（server.db[i].expires）中任意选择数据淘汰</li>
<li>allkeys-lru：从数据集（server.db[i].dict）中挑选最近最少使用的数据淘汰</li>
<li>allkeys-random：从数据集（server.db[i].dict）中任意选择数据淘汰</li>
<li>no-enviction（驱逐）：禁止驱逐数据</li>
</ul><div class="md-section-divider"></div><h3 data-anchor-id="17ln" id="请用redis和任意语言实现一段恶意登录保护的代码限制1小时内每用户id最多只能登录5次具体登录函数或功能用空函数即可不用详细写出">请用Redis和任意语言实现一段恶意登录保护的代码，限制1小时内每用户Id最多只能登录5次。具体登录函数或功能用空函数即可，不用详细写出。</h3><p data-anchor-id="h8am">用列表实现:列表中每个元素代表登陆时间,只要最后的第5次登陆时间和现在时间差不超过1小时就禁止登陆.用Python写的代码如下：</p><div class="md-section-divider"></div><pre class="prettyprint linenums prettyprinted" data-anchor-id="6851"><ol class="linenums"><li class="L0"><code><span class="com">#!/usr/bin/env python3</span></code></li><li class="L1"><code><span class="kwd">import</span><span class="pln"> redis  </span></code></li><li class="L2"><code><span class="kwd">import</span><span class="pln"> sys  </span></code></li><li class="L3"><code><span class="kwd">import</span><span class="pln"> time</span></code></li><li class="L4"><code></code></li><li class="L5"><code><span class="pln">r </span><span class="pun">=</span><span class="pln"> redis</span><span class="pun">.</span><span class="typ">StrictRedis</span><span class="pun">(</span><span class="pln">host</span><span class="pun">=’</span><span class="lit">127.0</span><span class="pun">.</span><span class="lit">0.1</span><span class="pun">′,</span><span class="pln"> port</span><span class="pun">=</span><span class="lit">6379</span><span class="pun">,</span><span class="pln"> db</span><span class="pun">=</span><span class="lit">0</span><span class="pun">)</span><span class="pln">  </span></code></li><li class="L6"><code><span class="kwd">try</span><span class="pun">:</span><span class="pln">  </span></code></li><li class="L7"><code><span class="pln">    id </span><span class="pun">=</span><span class="pln"> sys</span><span class="pun">.</span><span class="pln">argv</span><span class="pun">[</span><span class="lit">1</span><span class="pun">]</span></code></li><li class="L8"><code><span class="kwd">except</span><span class="pun">:</span><span class="pln">  </span></code></li><li class="L9"><code><span class="pln">    </span><span class="kwd">print</span><span class="pun">(‘</span><span class="pln">input argument error</span><span class="pun">’)</span></code></li><li class="L0"><code><span class="pln">    sys</span><span class="pun">.</span><span class="kwd">exit</span><span class="pun">(</span><span class="lit">0</span><span class="pun">)</span></code></li><li class="L1"><code></code></li><li class="L2"><code><span class="kwd">if</span><span class="pln"> r</span><span class="pun">.</span><span class="pln">llen</span><span class="pun">(</span><span class="pln">id</span><span class="pun">)</span><span class="pln"> </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="lit">5</span><span class="pln"> </span><span class="kwd">and</span><span class="pln"> time</span><span class="pun">.</span><span class="pln">time</span><span class="pun">()</span><span class="pln"> </span><span class="pun">–</span><span class="pln"> </span><span class="kwd">float</span><span class="pun">(</span><span class="pln">r</span><span class="pun">.</span><span class="pln">lindex</span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> </span><span class="lit">4</span><span class="pun">))</span><span class="pln"> </span><span class="pun">&lt;=</span><span class="pln"> </span><span class="lit">3600</span><span class="pun">:</span><span class="pln">  </span></code></li><li class="L3"><code><span class="pln">    </span><span class="kwd">print</span><span class="pun">(“</span><span class="pln">you are forbidden logining</span><span class="pun">”)</span></code></li><li class="L4"><code><span class="kwd">else</span><span class="pun">:</span><span class="pln">  </span></code></li><li class="L5"><code><span class="pln">    </span><span class="kwd">print</span><span class="pun">(‘</span><span class="pln">you are allowed to login</span><span class="pun">’)</span></code></li><li class="L6"><code><span class="pln">    r</span><span class="pun">.</span><span class="pln">lpush</span><span class="pun">(</span><span class="pln">id</span><span class="pun">,</span><span class="pln"> time</span><span class="pun">.</span><span class="pln">time</span><span class="pun">())</span></code></li><li class="L7"><code><span class="pln">    </span><span class="com"># login_func()</span></code></li></ol></pre><div class="md-section-divider"></div><h3 data-anchor-id="4f9f" id="redis-最适合的场景">redis 最适合的场景</h3><p data-anchor-id="2m5d">Redis最适合所有数据in-momory的场景，虽然Redis也提供持久化功能，但实际更多的是一个disk-backed的功能，跟传统意义上的持久化有比较大的差别，那么可能大家就会有疑问，似乎Redis更像一个加强版的Memcached，那么何时使用Memcached,何时使用Redis呢?</p><p data-anchor-id="5zhl">如果简单地比较Redis与Memcached的区别，大多数都会得到以下观点：</p><ul data-anchor-id="t1uo">
<li>1 、Redis不仅仅支持简单的k/v类型的数据，同时还提供list，set，zset，hash等数据结构的存储。</li>
<li>2 、Redis支持数据的备份，即master-slave模式的数据备份。</li>
<li>3 、Redis支持数据的持久化，可以将内存中的数据保持在磁盘中，重启的时候可以再次加载进行使用。</li>
</ul><div class="md-section-divider"></div><h4 data-anchor-id="rzbr" id="1会话缓存session-cache">（1）、会话缓存（Session Cache）</h4><p data-anchor-id="ob3l">最常用的一种使用Redis的情景是会话缓存（session cache）。用Redis缓存会话比其他存储（如Memcached）的优势在于：Redis提供持久化。当维护一个不是严格要求一致性的缓存时，如果用户的购物车信息全部丢失，大部分人都会不高兴的，现在，他们还会这样吗？</p><p data-anchor-id="5qpu">幸运的是，随着 Redis 这些年的改进，很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。</p><div class="md-section-divider"></div><h4 data-anchor-id="lxry" id="2全页缓存fpc">（2）、全页缓存（FPC）</h4><p data-anchor-id="idgv">除基本的会话token之外，Redis还提供很简便的FPC平台。回到一致性问题，即使重启了Redis实例，因为有磁盘的持久化，用户也不会看到页面加载速度的下降，这是一个极大改进，类似PHP本地FPC。</p><p data-anchor-id="nu5a">再次以Magento为例，Magento提供一个插件来使用Redis作为全页缓存后端。</p><p data-anchor-id="jpqq">此外，对WordPress的用户来说，Pantheon有一个非常好的插件  wp-redis，这个插件能帮助你以最快速度加载你曾浏览过的页面。</p><div class="md-section-divider"></div><h4 data-anchor-id="ipx8" id="3队列">（3）、队列</h4><p data-anchor-id="ktw6">Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作，这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作，就类似于本地程序语言（如Python）对 list 的 push/pop 操作。</p><p data-anchor-id="rvgg">如果你快速的在Google中搜索“Redis queues”，你马上就能找到大量的开源项目，这些项目的目的就是利用Redis创建非常好的后端工具，以满足各种队列需求。例如，Celery有一个后台就是使用Redis作为broker，你可以从这里去查看。</p><div class="md-section-divider"></div><h4 data-anchor-id="t86n" id="4排行榜计数器">（4），排行榜/计数器</h4><p data-anchor-id="je5z">Redis在内存中对数字进行递增或递减的操作实现的非常好。集合（Set）和有序集合（Sorted Set）也使得我们在执行这些操作的时候变的非常简单，Redis只是正好提供了这两种数据结构。所以，我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”，我们只需要像下面一样执行即可：</p><p data-anchor-id="q9lo">当然，这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数，你需要这样执行：</p><p data-anchor-id="adl1">ZRANGE user_scores 0 10 WITHSCORES</p><p data-anchor-id="23h1">Agora Games就是一个很好的例子，用Ruby实现的，它的排行榜就是使用Redis来存储数据的，你可以在这里看到。</p><div class="md-section-divider"></div><h4 data-anchor-id="is93" id="5发布订阅">（5）、发布/订阅</h4><p data-anchor-id="ymxw">最后（但肯定不是最不重要的）是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用，还可作为基于发布/订阅的脚本触发器，甚至用Redis的发布/订阅功能来建立聊天系统！（不，这是真的，你可以去核实）。</p></div>
</body>
</html>